Expand description
Rust bindings for Pieter Wuille’s secp256k1 library, which is used for fast and accurate manipulation of ECDSA signatures on the secp256k1 curve. Such signatures are used extensively by the Bitcoin network and its derivatives.
To minimize dependencies, some functions are feature-gated. To generate
random keys or to re-randomize a context object, compile with the
rand-std
feature. If you are willing to use the rand-std
feature, we
have enabled an additional defense-in-depth sidechannel protection for
our context objects, which re-blinds certain operations on secret key
data. To de/serialize objects with serde, compile with “serde”.
Important: serde
encoding is not the same as consensus
encoding!
Where possible, the bindings use the Rust type system to ensure that
API usage errors are impossible. For example, the library uses context
objects that contain precomputation tables which are created on object
construction. Since this is a slow operation (10+ milliseconds, vs ~50
microseconds for typical crypto operations, on a 2.70 Ghz i7-6820HQ)
the tables are optional, giving a performance boost for users who only
care about signing, only care about verification, or only care about
parsing. In the upstream library, if you attempt to sign a message using
a context that does not support this, it will trigger an assertion
failure and terminate the program. In rust-secp256k1
, this is caught
at compile-time; in fact, it is impossible to compile code that will
trigger any assertion failures in the upstream library.
use secp256k1::rand::rngs::OsRng;
use secp256k1::{Secp256k1, Message};
use secp256k1::hashes::sha256;
let secp = Secp256k1::new();
let (secret_key, public_key) = secp.generate_keypair(&mut OsRng);
let message = Message::from_hashed_data::<sha256::Hash>("Hello World!".as_bytes());
let sig = secp.sign_ecdsa(&message, &secret_key);
assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
If the “global-context” feature is enabled you have access to an alternate API.
use secp256k1::{generate_keypair, Message};
use secp256k1::hashes::sha256;
let (secret_key, public_key) = generate_keypair(&mut rand::thread_rng());
let message = Message::from_hashed_data::<sha256::Hash>("Hello World!".as_bytes());
let sig = secret_key.sign_ecdsa(message);
assert!(sig.verify(&message, &public_key).is_ok());
The above code requires rust-secp256k1
to be compiled with the rand-std
and bitcoin-hashes-std
feature enabled, to get access to generate_keypair
Alternately, keys and messages can be parsed from slices, like
use secp256k1::{Secp256k1, Message, SecretKey, PublicKey};
let secp = Secp256k1::new();
let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order");
let public_key = PublicKey::from_secret_key(&secp, &secret_key);
// This is unsafe unless the supplied byte slice is the output of a cryptographic hash function.
// See the above example for how to use this library together with `bitcoin-hashes-std`.
let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
let sig = secp.sign_ecdsa(&message, &secret_key);
assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
Users who only want to verify signatures can use a cheaper context, like so:
use secp256k1::{Secp256k1, Message, ecdsa, PublicKey};
let secp = Secp256k1::verification_only();
let public_key = PublicKey::from_slice(&[
0x02,
0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55,
0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8,
0xdb, 0x95, 0xe1, 0x56, 0x31, 0xce, 0x35, 0x8c,
0x3a, 0x17, 0x10, 0xc9, 0x62, 0x67, 0x90, 0x63,
]).expect("public keys must be 33 or 65 bytes, serialized according to SEC 2");
let message = Message::from_slice(&[
0xaa, 0xdf, 0x7d, 0xe7, 0x82, 0x03, 0x4f, 0xbe,
0x3d, 0x3d, 0xb2, 0xcb, 0x13, 0xc0, 0xcd, 0x91,
0xbf, 0x41, 0xcb, 0x08, 0xfa, 0xc7, 0xbd, 0x61,
0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50,
]).expect("messages must be 32 bytes and are expected to be hashes");
let sig = ecdsa::Signature::from_compact(&[
0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a,
0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a,
0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94,
0x0b, 0x55, 0x86, 0x82, 0x3d, 0xfd, 0x02, 0xae,
0x3b, 0x46, 0x1b, 0xb4, 0x33, 0x6b, 0x5e, 0xcb,
0xae, 0xfd, 0x66, 0x27, 0xaa, 0x92, 0x2e, 0xfc,
0x04, 0x8f, 0xec, 0x0c, 0x88, 0x1c, 0x10, 0xc4,
0xc9, 0x42, 0x8f, 0xca, 0x69, 0xc1, 0x32, 0xa2,
]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes");
assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
Observe that the same code using, say signing_only
to generate a context would simply not compile.
Crate features/optional dependencies
This crate provides the following opt-in Cargo features:
std
- use standard Rust library, enabled by default.alloc
- use thealloc
standard Rust library to provide heap allocations.rand
- userand
library to provide random generator (e.g. to generate keys).rand-std
- userand
library with itsstd
feature enabled. (Impliesrand
.)bitcoin-hashes
- use thebitcoin_hashes
library.bitcoin-hashes-std
- use thebitcoin_hashes
library with itsstd
feature enabled (impliesbitcoin-hashes
).recovery
- enable functions that can compute the public key from signature.lowmemory
- optimize the library for low-memory environments.global-context
- enable use of global secp256k1 context (impliesstd
).serde
- implements serialization and deserialization for types in this crate usingserde
. Important:serde
encoding is not the same as consensus encoding!
Re-exports
pub use bitcoin_hashes as hashes;
pub use rand;
pub use secp256k1_sys as ffi;
pub use serde;
pub use crate::scalar::Scalar;
Modules
global-context
and std
Secp256k1
context.Macros
Structs
Parity
fails.x
in an ECDSA signature.Enums
alloc
alloc
alloc
Statics
global-context
and std
Traits
'a
Message
s without any error paths.Secp256k1
can be used for verification.Functions
global-context
and rand
SECP256K1
context.